# Virtual Router Simulator 
#
# Copyright (C) 2009-2010 VRSim Project
# Author: Choonho Son <choonho@kt.com>
# URL: <http://vrsim.googlecode.com>
# For license information, see LICENSE.TXT
#

import xmlrpclib
import socket
import thread
import sys
import os,  re
import codecs

from time import sleep,  time
from PyQt4 import QtGui,  QtCore

import VRSim.Globals as globals
from VRSim.Utils import debug,  message,  splash
from VRSim.Ui.NodesLog import NodesLog
from VRSim.Node.Cisco import Cisco

class VMAPIMon:
    def __init__(self,  uri):
        self.uri = uri
        self.id = globals.GApp.userid
        self.pw = globals.GApp.passwd
        self.isInitialized = False
        
        self.initialize()
        
    def initialize(self):
        if True:
        #try:
            # Version check
            ver = self.getVersion()
            if ver > globals.INTVER:
                msg = "Version check failed client(%s) vs server(%s)\nUpdate client program" % (globals.INTVER,  ver)
                message(msg,  "critical")
                sys.exit()
                
            # Login check
            tf = self.login(self.id,  self.pw)
            if tf == False:
                message("Login(%s) failed" % self.id)
                return False
                
            # getReourceURL
            url = self.getResourceURL()
            if url == False:
                message("getResourceURL failed")
                sys.exit()
                
            # getResource check
            tf = self.getResource()
            if tf == False:
                message("VMAPI getResource failed, connect another Server",  "critical")
                sys.exit()
                
            self.tcpunused = set()
            for i in range(self.tcprange):
                self.tcpunused.add(self.tcpindex+i)
            self.tcpused = set()
            self.udpunused = set()
            for i in range(self.udprange):
                self.udpunused.add(self.udpindex+i)
            self.udpused = set()
        
            self.isInitialized = True
            # thread for heart BIT (update TTL)
            thread.start_new_thread(self.updateTTL,  ())
        else:
        #except:
            msg = "Cannot initialize VMAPIMon for %s" % self.uri
            message(msg,  "critical")
            return False
            
    def updateTTL(self):
        """ thread for heart bit
            every time (heartbit_interval), call updateTTL()
        """
        s = xmlrpclib.ServerProxy(self.uri)
        count = 0
        while 1:
            try:
                ret = s.updateTTL()
                msg = "Check server state (%s) : count(%s)" % (self.uri,  count)
                globals.GApp.workspace.status_message.setText(msg)
                count = count + 1
                #print msg
            except:
                msg = "Cannot connect VMServer %s" % self.uri
                globals.GApp.mainWindow.NodesLog.addError(msg)
                #debug("updateTTL: Cannot connect RPC: " + self.uri)
            
            # idlepc update
            try:
                nodes = globals.GApp.topology.nodes.keys()
                for key in nodes:
                    node = globals.GApp.topology.nodes[key]
                    if isinstance(node.physnode,  Cisco) == True and node.physnode.state == globals.START and node.physnode.idlepc == None:
                        # update idlepc
                        if node.physnode.idlepc_count > 5:
                            node.physnode.updateIdlepc()
                            msg = "idlepc of %s is not set\nupdate now!" % node.physnode.hostname
                            print msg
                        else:
                            node.physnode.idlepc_count = node.physnode.idlepc_count + 1
            except:
                msg = "idlepc check failed!"
                debug(msg)
            sleep(globals.heartbit_interval)
           
     
    def getVersion(self):
        """ check version between client and server
        """
        try:
            s = xmlrpclib.ServerProxy(self.uri)
            ver = s.getVersion()
            return ver
        except:
            msg = "VMAPIMon getVersion failed"
            message(msg,  "critical")
            return -1
            
    def login(self,  id ,  pw):
        """ authentication for resource
        after login succeed, there is a directory for id in server
        """
        msg = "Called login"
        #splash(msg)
        globals.GApp.my_logger.debug(msg)
        #try:
        s = xmlrpclib.ServerProxy(self.uri)
        tf = s.login(id,  pw)
        print "LOGIN Tf:", tf
            #socket.setdefaulttimeout(10)
        msg = "VMAPIMon login try result %s" % tf
        globals.GApp.my_logger.debug(msg)
        globals.GApp.authenticated = tf
        return tf
        #except:
        #    msg = "XMLRPC Error -- VMAPIMon fail to login (%s)" % self.uri
        #    globals.GApp.my_logger.critical(msg)
        #    return True

            
    def getVersion(self):
        """ get VMAPI Version
        """
        try:
            s = xmlrpclib.ServerProxy(self.uri)
            ver = s.getVersion()
            return ver
        except:
            return False
        
    def getResourceURL(self):
        """ get resource URL
        update hypervisors infrmation
        """
        try:
            s = xmlrpclib.ServerProxy(self.uri)
            url = s.getResourceURL()
            if url == False:
                error = "Cannot get Resource URL from (%s)" % self.uri
                message(error,  "critical")
                return False
            globals.GApp.topology.updateResourceURL(url,  self.uri)
            return True
        except:
            return False
            
    def getResource(self):
        try:
            s = xmlrpclib.ServerProxy(self.uri)
            ret = s.getResource()
            print "getResource return:",  ret
            [id,  [ta, tb],  [ua,  ub],  ttl] = ret
            self.tcpindex = ta
            self.tcprange = tb - ta
            self.udpindex = ua
            self.udprange = ub - ua
            msg = globals.eventMsg["getResource"]
            nmsg = msg % self.uri
            globals.GApp.mainWindow.NodesLog.addEvent(nmsg)
            globals.dynamips_console = self.tcpindex
            return True
        except:
            debug("getResource: Cannot connect RPC: " + self.uri )
            return False
            """
            self.tcpindex = 10000
            self.tcprange = 100
            self.udpindex = 10000
            self.udprange = 1000
            """
        
    def releaseResource(self):
        try:
            s = xmlrpclib.ServerProxy(self.uri)
            ret = s.releaseResource()
            return True
        except:
            debug("VMAPI: Cannot release Resource")
            return False
            
    
    #####################################################
    # RPC : directory or file manuplation
    # listDir, getImgDir, getMyDir, copy, rename. delete
    #####################################################
    def listDir(self,  path):
        try:
            s = xmlrpclib.ServerProxy(self.uri)
            ret = s.listDir(path)
            print "return listDir",  ret
            return ret
        except:
            debug("VMAPI: Cannot getDir")
            
            
    def getImgDir(self):
        try:
            s = xmlrpclib.ServerProxy(self.uri)
            ret = s.getImgDir()
            print "return getImgDir:",  ret
            return ret
        except:
            debug("VMAPI: Cannot getImgDir")
    
    def getMyDir(self):
        """ return User's project directory
        """
        try:
            s = xmlrpclib.ServerProxy(self.uri)
            ret = s.getMyDir()
            print "return getMyDir:",  ret
            return ret
        except:
            debug("VMAPI: Cannot getMyDir")
    
    def copy(self,  src,  dst):
        """ copy src  to dst
        """
        
        try:
            pic = QtGui.QPixmap(":/symbols/loading_1.png")
            pic2 = QtGui.QPixmap(":/symbols/loading_6.png")
            splash = QtGui.QSplashScreen(pic,  QtCore.Qt.WindowStaysOnTopHint)
            progressBar = QtGui.QProgressBar(splash)
            progressBar.setGeometry(1, 9*splash.height()/10,
                        splash.width() - 1, splash.height()/10)
            
            #splash.showMessage("Copying Data........",  QtCore.Qt.AlignBottom | QtCore.Qt.yellow)
            progressBar.setMinimum(0)
            progressBar.setMaximum(0)
            splash.show()

            #for i in range(0, 40):
            #    progressBar.setValue(i)

            globals.GApp.processEvents()
            s = xmlrpclib.ServerProxy(self.uri)
            ret = s.copy(src, dst)
            
            splash.setPixmap(pic2)
            
            for i in range(40, 100):
                progressBar.setValue(i)

            t = time()
            while time() < t + 0.1:
                globals.GApp.processEvents()
            

            return ret
        except:
            debug("VMAPI: Cannot copy")
        
    def rename(self,  src,  dst):
        """ rename src file to dst file
        """
        try:
            s = xmlrpclib.ServerProxy(self.uri)
            ret = s.rename(src, dst)
            return ret
        except:
            debug("VMAPIMon: Cannot rename")
            return False
    
    def delete(self,  src):
        """ delete file
        """
        try:
            s = xmlrpclib.ServerProxy(self.uri)
            ret = s.delete(src)
            return ret
        except:
            debug("VMAPIMon: Cannot delete")
            return False
            
    def mkdir(self,  src):
        """ mkdir directory
        """
        try:
            s = xmlrpclib.ServerProxy(self.uri)
            ret = s.mkdir(src)
            return ret
        except:
            debug("VMAPIMon: Cannot make directory")
            return False
    
    def upload(self,  file,  directory):
        """ upload file to directory
        """
        msg = "upload file(%s) to dir(%s)" % (file, directory)
        print msg
        
        # file size check
        # cannot upload file more than 1 MB
        fsize = os.path.getsize(file)
        if fsize > 1000 * 1000 * 8:
            msg = "Cannot upload file more than 1MB"
            message(msg)
            return False
            
        # try
        s = xmlrpclib.ServerProxy(self.uri)
        temp = file.split("/")
        strfp = temp[-1]
        fullpath = "%s/%s" % (directory,  strfp)
        debug("upload filename:%s" % fullpath)
        
        #content = xmlrpclib.Binary(open(file).read())
        content = xmlrpclib.Binary(open(file).read())
        
        s.upload(str(content),  fullpath)
       
    def download(self,  filename):
        """ download file from server
        """
        msg = "download (%s)" % filename
        debug(msg)
        # try:
        s = xmlrpclib.ServerProxy(self.uri)
            
        # choose destination folder
        dirname = QtGui.QFileDialog.getExistingDirectory(None,  "Choose save directory",  "./",  QtGui.QFileDialog.ShowDirsOnly | QtGui.QFileDialog.DontResolveSymlinks)
        if not dirname:
            msg = "You have to select directory for saving"
            message(msg,  "error")
            return False
            
        # get filename
        temp = filename.split("/")
        strfp = temp[-1]
    
        dirname2 = unicode(dirname).encode(globals.ENCODING)
        fullpath = "%s/%s" % (dirname2,  strfp)
        msg = "Save at (%s)" % fullpath
        debug(msg)
        
        # write
        with open(fullpath, "w") as handle:
            handle.write(s.download(filename).data)

        return True 
        
    def exists(self,  file):
        """ check file exists?
        """
        try:
            s = xmlrpclib.ServerProxy(self.uri)
            ret = s.exists(file)
            return ret
        except:
            debug("VMAPIMon: Cannot exists check")
            return False
    
    def requestTCP(self):
        """ return unused tcp port 
        """
        new_tcp = self.tcpunused.pop()
        self.tcpused.add(new_tcp)
        debug("requestTCP:" + str(new_tcp))
        return new_tcp
        
    def releaseTCP(self,  tcp):
        """ release used TCP port
        """
        self.tcpused.remove(tcp)
        self.tcpunused.add(tcp)
        
    def requestUDP(self):
        new_udp = self.udpunused.pop()
        self.udpused.add(new_udp)
        msg = "requestUDP : %s" % new_udp
        debug(msg)
        return new_udp
        
    def releaseUDP(self,  udp):
        self.udpused.remove(udp)
        self.udpunused.add(udp)
        
        
